//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "USBCANInterface.h"

//---------------------------------------------------------------------------

#pragma package(smart_init)


int __fastcall TUSBCANInterface::SendMsg(int id, byte * msg, Cardinal dlc, Cardinal flags)
{
  unsigned long  NoOfBytes;
  Byte StdMsg[16];

  #if DebugUSBCANInt == 1
  Debug( "USBCAN-SendMsg Length = " + IntToStr( dlc ));
  #endif

  if( flags == USBCanMSG )
    FT_W32_WriteFile( CurrentFTHandle, msg, dlc, &NoOfBytes, NULL );
  else if( flags == canMSG_STD )
  {
    StdMsg[0] = 1;
    StdMsg[1] = 10;
    StdMsg[2] = dlc + 2;
    StdMsg[3] = id & 255;
    StdMsg[4] = id >> 8;
    //for( int i = 5; i <= 4 + dlc; i++ ) StdMsg[i] = msg[i-5];
    Move(msg, StdMsg + 5, dlc);
    StdMsg[5 + dlc] = 4;
    FT_W32_WriteFile( CurrentFTHandle, StdMsg, dlc + 6, &NoOfBytes, NULL );
    NoOfBytes -= 6;

  #if DebugUSBCANInt == 1
  Debug( "USBCAN-SendMsg Sent Length = " + IntToStr( NoOfBytes ));
  #endif

  }
  return NoOfBytes;
}

//---------------------------------------------------------------------------

bool __fastcall TUSBCANInterface::CanBusOn()
{
	bool rslt;
	DWORD NoOfDevs, DevIndex;
	FT_STATUS ftStatus;
	String S1, S2;
	char USBCANSerNo[9] = "PR000001";

	CurrentFTHandle = INVALID_HANDLE_VALUE;

	ftStatus = FT_ListDevices(&NoOfDevs,NULL,FT_LIST_NUMBER_ONLY);
	if (ftStatus == FT_OK)
	{
		for( DevIndex = 0; DevIndex < NoOfDevs; DevIndex++ )
		{
			ftStatus = FT_ListDevices((PVOID)DevIndex,USBCANSerNo,FT_LIST_BY_INDEX|FT_OPEN_BY_SERIAL_NUMBER);
			if (ftStatus == FT_OK)
			{
				S1 = USBCANSerNo;
				if( S1.Pos("PRCII") == 1 || S1.Pos("PR000001") == 1 )
				{
					CurrentFTHandle = FT_W32_CreateFile( USBCANSerNo,
																							 GENERIC_READ | GENERIC_WRITE,
																							 0,
																							 NULL,
																							 OPEN_EXISTING,
																							 FILE_ATTRIBUTE_NORMAL | FT_OPEN_BY_SERIAL_NUMBER,
																							 NULL );
				}
			}
		}
	}



	if( CurrentFTHandle == INVALID_HANDLE_VALUE )
	{  
		CanBusStatus =  0;
	}
	else
	{
		CanBusStatus =  1;
		TimerCanRx->Enabled = true;
		SetCANPower( true );
		SetUSBCanAddress( 200 );
		USBCanVersion = GetUSBCanVersion();
		SetUSBCanActive( true );
		rslt = true;
	}
return rslt;
}

//---------------------------------------------------------------------------

bool __fastcall TUSBCANInterface::CanBusOff()
{
bool rslt;

SetUSBCanActive( false );
SetCANPower( false );

rslt = FT_W32_CloseHandle( CurrentFTHandle );
if( rslt == true ) CanBusStatus = 0;
else CanBusStatus = 2;

TimerCanRx->Enabled = False;

return rslt;
}


bool __fastcall TUSBCANInterface::CanBusOff_2()
{
bool rslt;

SetUSBCanActive( false );
//SetCANPower( false );

rslt = FT_W32_CloseHandle( CurrentFTHandle );
if( rslt == true ) CanBusStatus = 0;
else CanBusStatus = 2;

TimerCanRx->Enabled = False;

return rslt;
}

//---------------------------------------------------------------------------

__fastcall TUSBCANInterface::TUSBCANInterface( ProcMessFP SetPM, TDebugWin *SetDebugWin)
{
DW = SetDebugWin;
PM = SetPM;
TimerCanRx = new TTimer( NULL );
TimerCanRx->Enabled = False;
TimerCanRx->Interval = 100;
TimerCanRx->OnTimer = TimerCanRxEvent;
CANInBufReadPnt = 0;
CANInBufWritePnt = 0;

}

//---------------------------------------------------------------------------

bool __fastcall TUSBCANInterface::SetUSBCanAddress(Word USBCANAddress)
{
Byte msg[8];
Cardinal flag;

flag = USBCanMSG;
msg[0] = 1;
msg[1] = 11;
msg[2] = 2;
msg[3] = USBCANAddress & 255;
msg[4] = USBCANAddress >> 8;
msg[5] = 4;

if( SendMsg( 0, msg, 6, flag ) == 6 )
  #if DebugUSBCANInt == 1
  Debug( "Set USBCANAddress")
  #endif
  ;
else
  #if DebugUSBCANInt == 1
  Debug( "ERR while setting USBCANAddress")
  #endif
  ;
}
//---------------------------------------------------------------------------

bool __fastcall TUSBCANInterface::SetUSBCanActive(bool Status)
{
Byte msg[8];
Cardinal flag;

flag = USBCanMSG;
msg[0] = 1;
msg[1] = 16;
msg[2] = 1;
if( Status ) msg[3] = 1;
else msg[3] = 0;
msg[4] = 4;


if( SendMsg( 0, msg, 5, flag ) == 5 )
  #if DebugUSBCANInt == 1
  Debug( "Set USBCANActive = " + IntToStr( msg[3] ))
  #endif
  ;
else
  #if DebugUSBCANInt == 1
  Debug( "ERR while setting USBCANActive")
  #endif
  ;
}

//---------------------------------------------------------------------------

bool __fastcall TUSBCANInterface::SetCANPower(bool Status)
{
Byte msg[8];
Cardinal flag;

flag = USBCanMSG;
msg[0] = 1;
msg[1] = 15;
msg[2] = 1;
if( Status ) msg[3] = 1;
else msg[3] = 0;
msg[4] = 4;


if( SendMsg( 0, msg, 5, flag ) == 5 )
  #if DebugUSBCANInt == 1
  Debug( "Set CANPower = " + IntToStr( msg[3] ))
  #endif
  ;
else
  #if DebugUSBCANInt == 1
  Debug( "ERR while setting CANPower")
  #endif
  ;
}

//---------------------------------------------------------------------------

int __fastcall TUSBCANInterface::GetUSBCanVersion()
{
Byte msg[8];
Cardinal flag;

flag = USBCanMSG;
msg[0] = 1;
msg[1] = 12;
msg[2] = 0;
msg[3] = 4;

if( SendMsg( 0, msg, 4, flag ) == 4 )
  #if DebugUSBCANInt == 1
  Debug( "Request USBCANVersion")
  #endif
  ;
else
  #if DebugUSBCANInt == 1
  Debug( "ERR while requesting USBCANVersion")
  #endif
  ;
}

//---------------------------------------------------------------------------

void __fastcall TUSBCANInterface::Debug(String Message)
{
  if( DW != NULL ) DW->Log(Message);
}

//---------------------------------------------------------------------------


bool __fastcall TUSBCANInterface::SetAOut(Word CanAdr, int Value)
{
Byte msg[8];
Cardinal flag;
double DVal;
int IntVal;

flag = canMSG_STD;

DVal = Value; DVal = DVal * 65535.0 / 4570.0;
IntVal = DVal;
IntVal = max( min( IntVal, 65535 ), 0 );

msg[0] = 2;
msg[1] = IntVal & 255;
msg[2] = IntVal >> 8;

/* TODO 1 : Check resulting output for AOUT */

if( SendMsg( CanAdr, msg, 3, flag ) == 3 )
  #if DebugUSBCANInt == 1
  Debug( "Set AOut " + IntToStr(Value) + " on CanAdr " + IntToStr(CanAdr) )
  #endif
  ;
else
  #if DebugUSBCANInt == 1
  Debug( "TX ERR while sending AOut to " + IntToStr(CanAdr) )
  #endif
  ;
}
//---------------------------------------------------------------------------


bool __fastcall TUSBCANInterface::SetPSVOut(Word CanAdr, int Value)
{
Byte msg[8];
Cardinal flag;

int IntVal;

flag = canMSG_STD;

IntVal = max( min( Value, 20000 ), 0 );

msg[0] = 26;
msg[1] = IntVal & 255;
msg[2] = IntVal >> 8;
msg[3] = 1;

if( SendMsg( CanAdr, msg, 4, flag ) == 4 )
	#if DebugUSBCANInt == 1
	Debug( "Set PSVOut = " + IntToStr(Value) + " on CanAdr " + IntToStr(CanAdr) )
	#endif
	;
else
	#if DebugUSBCANInt == 1
	Debug( "TX ERR while sending PSVOut to " + IntToStr(CanAdr) )
	#endif
	;
}
//---------------------------------------------------------------------------


bool __fastcall TUSBCANInterface::SetPSIOut(Word CanAdr, int Value)
{
Byte msg[8];
Cardinal flag;

int IntVal;

flag = canMSG_STD;

IntVal = max( min( Value, 10000 ), 0 );

msg[0] = 26;
msg[1] = IntVal & 255;
msg[2] = IntVal >> 8;
msg[3] = 0;

if( SendMsg( CanAdr, msg, 4, flag ) == 4 )
	#if DebugUSBCANInt == 1
	Debug( "Set PSIOut = " + IntToStr(Value) + " on CanAdr " + IntToStr(CanAdr) )
	#endif
	;
else
	#if DebugUSBCANInt == 1
	Debug( "TX ERR while sending PSIOut to " + IntToStr(CanAdr) )
	#endif
	;
}
//---------------------------------------------------------------------------

bool __fastcall TUSBCANInterface::SetDigOut(Word CanAdr, Word Channel, bool Status)
{
Byte msg[8];
Cardinal flag;

flag = canMSG_STD;
msg[0] = 5;
msg[1] = Channel;
if( Status == true ) msg[2] = 1;
else msg[2] = 0;

if( SendMsg( CanAdr, msg, 3, flag ) == 3 )
	#if DebugUSBCANInt == 1
  Debug( "Set DigOut " + IntToStr(Channel) + " to " + IntToStr(msg[2]) + " on CanAdr " + IntToStr(CanAdr) )
  #endif
  ;
else
	#if DebugUSBCANInt == 1
  Debug( "TX ERR while sending DigOut to " + IntToStr(CanAdr) )
  #endif
	;
}

//---------------------------------------------------------------------------

bool __fastcall TUSBCANInterface::SetPSOutputOn(Word CanAdr, bool Status)
{
Byte msg[8];
Cardinal flag;

flag = canMSG_STD;
msg[0] = 20;
if( Status == true ) msg[1] = 0;
else msg[1] = 1;

if( SendMsg( CanAdr, msg, 2, flag ) == 2 )
	#if DebugUSBCANInt == 1
	Debug( "PS Output On = " + IntToStr(msg[1]) + " on CanAdr " + IntToStr(CanAdr) )
	#endif
	;
else
	#if DebugUSBCANInt == 1
	Debug( "TX ERR while sending PS Output On " + IntToStr(CanAdr) )
  #endif
	;
}
//---------------------------------------------------------------------------

bool __fastcall TUSBCANInterface::SetPSMode(Word CanAdr, int Status)
{
Byte msg[8];
Cardinal flag;

flag = canMSG_STD;
msg[0] = 23;
if( Status == 1 ) msg[1] = 1;
else msg[1] = 0;

if( SendMsg( CanAdr, msg, 2, flag ) == 2 )
	#if DebugUSBCANInt == 1
	Debug( "PSMode = " + IntToStr(msg[1]) + " on CanAdr " + IntToStr(CanAdr) )
  #endif
  ;
else
	#if DebugUSBCANInt == 1
  Debug( "TX ERR while sending PSMode to " + IntToStr(CanAdr) )
  #endif
	;
}
//---------------------------------------------------------------------------
void __fastcall TUSBCANInterface::TimerCanRxEvent(TObject * Sender)
{
  int MOffset, MStart, MEnd, MLength;
  bool rslt, Search;
  unsigned long NoOfBytes, NoOfBytesRead;
  /*
  #if DebugUSBCANInt == 1
  Debug( "USBCAN-CanRxEvent" );
  #endif
  */
  if( FT_GetQueueStatus(CurrentFTHandle, &NoOfBytes) != FT_OK ) NoOfBytes = 0;

  /*
  #if DebugUSBCANInt == 1
  Debug( "USBCAN-CanRxEvent Bytes in Queue = " + IntToStr( NoOfBytes ));
  #endif
  */



  NoOfBytes = min( NoOfBytes, (unsigned long)(TempCANBufSize - MaxUSBMeassageLength) );
  if( NoOfBytes > 0 )
  {

    #if DebugUSBCANInt == 1
    Debug( "USBCAN-CanRxEvent Bytes requested = " + IntToStr( NoOfBytes ));
    #endif


    // Copy to CANInBuf
    FT_W32_ReadFile( CurrentFTHandle, TempCANBuf, NoOfBytes, &NoOfBytesRead, NULL );

    #if DebugUSBCANInt == 1
    Debug( "USBCAN-CanRxEvent Bytes read = " + IntToStr( NoOfBytesRead ));
    #endif

    for( int i = 0; i < NoOfBytesRead; i++ )
      CANInBuf[CANInBufWritePnt++ & BufMask] = TempCANBuf[i];

    // Search for meassage
    while( CANInBufReadPnt < CANInBufWritePnt )
    {
      if( CANInBuf[CANInBufReadPnt & BufMask] == 1 )
      {
        MStart = CANInBufReadPnt;
        MLength = CANInBuf[(MStart + 2) & BufMask];
        MEnd = MStart + MLength + 3;
        if( MEnd >=  CANInBufWritePnt ) break;
        else
        {
          if( CANInBuf[MEnd & BufMask] == 4 )  // accept as meassage
          {
            if( CANInBuf[(MStart + 1) & BufMask] == 20 )  // meassge from CANBUSS
            {
              for( int i = 0; i < MLength - 1; i++ ) // copy meassage to CANInBuf
                CANInMsg[i] = CANInBuf[(MStart + USBHeaderLength + i) & BufMask];

              // handle meassage
              CANInBufReadPnt = MEnd + 1;
              CANInFlg = canMSG_STD;

              //CanRx(nil);    <<<<---------------------------------------------
              PM( CANInMsg );


            } //if( CANInBuf[MStart + 1] == 20
            else if( CANInBuf[(MStart + 1) & BufMask] == 23 )  // meassge CANStatus
            {
              #if DebugUSBCANInt == 1
              Debug( "Error =  " + IntToStr(CANInBuf[(MStart + 3) & BufMask]));
              #endif
              CANInBufReadPnt = MEnd + 1;
            }
            else  // message from USBCAN interface
            {
              CANInBufReadPnt = MEnd + 1;
            }
          } // if( CANInBuf[MEnd] == 4
        } // if( MEnd <=  CANInBufWritePnt
      } // if( CANInBuf[i] == 1 )
      else
      {
         CANInBufReadPnt++;
      }
    } // while CANInBufReadPnt < CANInBufWritePnt
    CANInBufReadPnt = CANInBufReadPnt & BufMask;
    CANInBufWritePnt = CANInBufWritePnt & BufMask;
    if( CANInBufWritePnt < CANInBufReadPnt )
      CANInBufWritePnt = CANInBufWritePnt + BufMask + 1;

  } // if( NoOfBytes > 0 )
}

//---------------------------------------------------------------------------

void __fastcall TUSBCANInterface::SetDebugWin( TDebugWin *SetDebugWin )
{
  DW = SetDebugWin;
}


